package cn.liujianbo.example.base.algorithm;

import java.util.Random;

/**
 * @author 刘建波
 * @date 2021-10-10 21:57
 * 负载均衡算法
 */
public class LoadBalance {
    private Server[] servers = {new Server("A", 3), new Server("B", 2), new Server("C", 5)};
    private String[] weightServers = new String[10];

    public static void main(String[] args) {
        LoadBalance loadBalance = new LoadBalance();

        /*// 轮询
        for (int i = 0; i < 10; i++) {
            System.out.println(loadBalance.polling(i));
        }

        // 随机
        for (int i = 0; i < 10; i++) {
            System.out.println(loadBalance.random(i));
        }

        // 加权算法  空间换时间
        loadBalance.populateWeightServers();
        // 加权轮询
        for (int i = 0; i < 10; i++) {
            System.out.println(loadBalance.weightPolling1(i));
        }
        // 加权随机
        for (int i = 0; i < 10; i++) {
            System.out.println(loadBalance.weightRandom1(i));
        }
*/
        // 加权算法   时间换空间
        // 加权轮询
//        for (int i = 0; i < 10; i++) {
//            System.out.println(loadBalance.weightPolling2(i));
//        }
        // 加权随机
        for (int i = 0; i < 10; i++) {
            System.out.println(loadBalance.weightRandom2());
        }
    }
    
    /**
     * 轮询
     */
    private String polling(int count){
        int i = count % servers.length;
        return servers[i].name;
    }

    /**
     * 随机
     */
    private String random(int count){
        int i = new Random().nextInt(servers.length);
        return servers[i].name;
    }

    /**
     * 加权轮询 空间换时间
     */
    private String weightPolling1(int count){
        int i = count % weightServers.length;
        return weightServers[i];
    }

    /**
     * 加权随机 空间换时间
     */
    private String weightRandom1(int count){
        int i = new Random().nextInt(weightServers.length);
        return weightServers[i];
    }

    /**
     * 加权轮询 时间换空间
     */
    private String weightPolling2(int count){
        int length = servers.length;
        int[] weightSort = new int[length];
        String[] names = new String[length];
        for (int i = 0; i < servers.length; i++) {
            weightSort[i] = servers[i].weight;
            names[i] = servers[i].name;
        }

        for (int i = 0; i < weightSort.length; i++) {
            if (count - weightSort[i] <0) {
                return names[i];
            }
            count -= weightSort[i];
        }
        return "null";
    }

    /**
     * 加权随机 时间换空间
     */
    private String weightRandom2(){
        int i = new Random().nextInt(10);
        int sum = 0;
        for (Server server : servers) {
            sum += server.weight;
            if (sum > i) {
                return server.name;
            }
        }
        return "null";
    }

    private void populateWeightServers() {
        int index = 0;
        for (Server server : servers) {
            int weight = server.getWeight();
            for (int i = 0; i < weight; i++) {
                weightServers[index] = server.getName();
                index++;
            }
        }
    }

    private static class Server{
        private String name;
        private int weight;

        public Server(String name, int weight) {
            this.name = name;
            this.weight = weight;
        }

        public String getName() {
            return this.name;
        }

        public int getWeight() {
            return this.weight;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setWeight(int weight) {
            this.weight = weight;
        }

        public boolean equals(final Object o) {
            if (o == this) return true;
            if (!(o instanceof Server)) return false;
            final Server other = (Server) o;
            if (!other.canEqual((Object) this)) return false;
            final Object this$name = this.getName();
            final Object other$name = other.getName();
            if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
            if (this.getWeight() != other.getWeight()) return false;
            return true;
        }

        protected boolean canEqual(final Object other) {
            return other instanceof Server;
        }

        public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final Object $name = this.getName();
            result = result * PRIME + ($name == null ? 43 : $name.hashCode());
            result = result * PRIME + this.getWeight();
            return result;
        }

        public String toString() {
            return "LoadBalance.Server(name=" + this.getName() + ", weight=" + this.getWeight() + ")";
        }
    }
}
